package fontys.time;

/**
 *
 * @author willem Sporen, 2155777
 */
public class Period implements IPeriod {

    /**
     * Field for the starting time of this period.
     */
    private ITime beginTime;
    /**
     * Field for the ending time of this period.
     */
    private ITime endTime;

    /**
     * creation of a period with begin time bt and end time et.
     *
     * @param bt begin time of the period. bt is earlier than et
     * @param et endtime of the period
     *
     */
    public Period(final ITime bt, final ITime et) {
        if (bt.difference(et) <= 0) {
            throw new IllegalArgumentException("The end time may not occur"
                    + " before the begin time.");
        } else {
            this.beginTime = bt;
            this.endTime = et;
        }
    }

    @Override
    public final ITime getBeginTime() {
        return beginTime;
    }

    @Override
    public final ITime getEndTime() {
        return endTime;
    }

    @Override
    public final int length() {
        return (beginTime.difference(endTime));
    }

    @Override
    public final void setBeginTime(final ITime bT) {
        if (bT.difference(this.endTime) <= 0) {
            throw new IllegalArgumentException("The new begin date occurs after"
                    + " the ending date of this period.");
        }
        this.beginTime = bT;
    }

    @Override
    public final void setEndTime(final ITime eT) {
        if (this.beginTime.difference(eT) <= 0) {
            throw new IllegalArgumentException("The new end time occurs before"
                    + " the ending date of this period.");
        }
        this.endTime = eT;
    }

    @Override
    public final void move(final int minutes) {
        ITime newBeginTime = this.beginTime.plus(minutes);
        ITime newEndTime = this.endTime.plus(minutes);

        this.beginTime = new Time(newBeginTime.getYear(),
                newBeginTime.getMonth(), newBeginTime.getDay(),
                newBeginTime.getHours(), newBeginTime.getMinutes());

        this.endTime = new Time(newEndTime.getYear(),
                newEndTime.getMonth(), newEndTime.getDay(),
                newEndTime.getHours(), newEndTime.getMinutes());
    }

    @Override
    public final void changeLengthWith(final int minutes) {
        //Length must be pos!
        if (minutes <= 0) {
            throw new IllegalArgumentException("This value should be higher"
                    + " than zero.");
        }
        this.endTime = this.endTime.plus(minutes);
    }

    @Override
    public final boolean isPartOf(final IPeriod period) {
        return (this.beginTime.difference(period.getBeginTime()) <= 0
                && this.getEndTime().difference(period.getEndTime()) >= 0);
    }

    @Override
    public final IPeriod unionWith(final IPeriod period) {
        //Declare some temp fields
        IPeriod setA = null;
        IPeriod setB = null;
        ITime newBeginTime;
        ITime newEndTime;

        //Check which period starts first.
        if (this.getBeginTime().difference(period.getBeginTime()) >= 0) {
            //THIS begins first. This period becomes setA.
            setA = this;
            setB = period;
        } else if (period.getBeginTime().difference(this.getBeginTime()) >= 0) {
            setA = period;
            setB = this;
        }

        //Check if sets have a common intersection!
        if (setA.getEndTime().difference(setB.getBeginTime()) <= 0) {
            //Continue!
            // setA is always the first set. So we use setA's starting time.
            newBeginTime = setA.getBeginTime();
            //All we have to do now, is check whether setA or B's end time is
            //greater.
            if (setA.getEndTime().difference(setB.getEndTime()) <= 0) {
                //A's endtime is greater.
                newEndTime = setA.getEndTime();
            } else {
                newEndTime = setB.getEndTime();
            }
            //Now all we have to do is return a new period.
            return new Period(newBeginTime, newEndTime);
        } else {
            //We don't have a common intersection. Return null instead.
            return null;
        }
    }

    @Override
    public final IPeriod intersectionWith(final IPeriod period) {
        //Declare some temp fields
        IPeriod setA = null;
        IPeriod setB = null;
        ITime newBeginTime;
        ITime newEndTime;

        //Check which period starts first.
        if (this.getBeginTime().difference(period.getBeginTime()) >= 0) {
            //THIS begins first. This period becomes setA.
            setA = this;
            setB = period;
        } else if (period.getBeginTime().difference(this.getBeginTime()) >= 0) {
            setA = period;
            setB = this;
        }

        //Check if sets have a common intersection!
        if (setA.getEndTime().difference(setB.getBeginTime()) <= 0) {
            //Continue!
            // setA is always the first set.
            //All we have to do now, is check whether setA or B's begin time is
            //greater. Then check which end time is lesser.
            if (setA.getBeginTime().difference(setB.getBeginTime()) <= 0) {
                //A's beginTime is greater.
                newBeginTime = setA.getBeginTime();
            } else {
                newBeginTime = setB.getBeginTime();
            }
            if (setA.getEndTime().difference(setB.getEndTime()) >= 0) {
                newEndTime = setA.getEndTime();
            } else {
                newEndTime = setB.getEndTime();
            }
            //Now all we have to do is return a new period.
            return new Period(newBeginTime, newEndTime);
        } else {
            //We don't have a common intersection. Return null instead.
            return null;
        }
    }
}
